# 类加载器
# 以文件名作为功能名称
import os


class GzLoader:

    # class_dir: 类所在的目录名称， 如 tools
    def __init__(self, class_dir):
        self.class_dir = class_dir
        # 类容器
        self.class_dict = dict()
        # 类说明容器
        self.class_doc_dict = dict()
        # 遍历目录下的 .py文件， 并获取类名，然后拼接目录成完整类名
        for fn in os.listdir(class_dir):
            # 只处理目录下的 .py 文件
            if not fn.endswith('.py'):
                continue
            fun_name = fn[:fn.rindex('.py')]
            res = self.get_class_name(os.path.join(class_dir, fn))
            # 如果没有找到类名则跳过
            if not res[0]:
                continue
            self.class_dict[fun_name] = res[0]
            self.class_doc_dict[fun_name] = res[1]

    #  从类文件中获取类的名称和说明
    def get_class_name(self, file_name):
        class_name = None
        class_doc = None
        with open(file_name, 'r', encoding='utf-8') as fp:
            for line in fp.readlines():
                class_defined = line.strip()
                # 如果是以 “# @tip” 开头则默认后面是工具的说明
                if len(class_defined) > 6 and class_defined.startswith('# @tip'):
                    class_doc = class_defined[6:]
                    continue
                # 如果第一个单词是class 那么就认为当前行是类的定义行
                if class_defined.startswith('class'):
                    flag1 = class_defined.find('(')
                    flag2 = class_defined.index(':')
                    class_name = class_defined[6: flag1 if flag1 != -1 and flag1 < flag2 else flag2]
                    break
        return class_name, class_doc

    # 反射获取类
    def get_obj(self, fun_name):
        # 判断容器内是否有对应的类名
        if fun_name not in self.class_dict:
            return None
        # 动态加载模块
        modules = __import__(self.class_dir + '.' + fun_name)
        pack = getattr(modules, fun_name)
        # 返回类的类型
        return getattr(pack, self.class_dict[fun_name])

    # 获取功能说明列表
    def get_fun_list(self):
        return self.class_doc_dict
